package com.example.service.message.service;

import com.alibaba.fastjson.JSONObject;
import com.example.common.config.AppConfig;
import com.example.common.constant.ConsoleColors;
import com.example.common.constant.Constants;
import com.example.common.enums.ConversationTypeEnum;
import com.example.common.enums.DelFlagEnum;
import com.example.common.model.message.*;
import com.example.service.conversation.service.ConversationService;
import com.example.service.group.dao.ImGroupMessageHistoryEntity;
import com.example.service.group.dao.mapper.ImGroupMessageHistoryMapper;
import com.example.service.message.dao.ImMessageBodyEntity;
import com.example.service.message.dao.ImMessageHistoryEntity;
import com.example.service.message.dao.mapper.ImMessageBodyMapper;
import com.example.service.message.dao.mapper.ImMessageHistoryMapper;
import com.example.service.utils.SnowflakeIdWorker;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.ZSetOperations;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;

@Service
@Slf4j
public class MessageStoreService {

    @Autowired
    ImMessageHistoryMapper imMessageHistoryMapper;

    @Autowired
    ImMessageBodyMapper imMessageBodyMapper;

    @Autowired
    SnowflakeIdWorker snowflakeIdWorker;       //雪花算法

    @Autowired
    RabbitTemplate rabbitTemplate;

    @Autowired
    ImGroupMessageHistoryMapper imGroupMessageHistoryMapper;


    @Autowired
    StringRedisTemplate stringRedisTemplate;

    @Autowired
    ConversationService conversationService;

    @Autowired
    AppConfig appConfig;


    @Transactional
    public void storeP2PMessage(MessageContent messageContent){
//        //messageContent 转化成 messageBody
//        ImMessageBodyEntity imMessageBodyEntity = extractMessageBody(messageContent);
//        //插入messageBody
//        imMessageBodyMapper.insert(imMessageBodyEntity);
////        //转化成MessageHistory     这里使用的是写扩散 要给发消息的两个人都进行保存数据 每条数据的ownerId不同
//        List<ImMessageHistoryEntity> imMessageHistoryEntities = extractToP2PMessageHistory(messageContent, imMessageBodyEntity);
////        //批量插入
//        imMessageHistoryMapper.insertBatchSomeColumn(imMessageHistoryEntities);
//        messageContent.setMessageKey(imMessageBodyEntity.getMessageKey());

        ImMessageBody imMessageBodyEntity = extractMessageBody(messageContent);
        DoStoreP2PMessageDto dto = new DoStoreP2PMessageDto();
        dto.setMessageContent(messageContent);
        dto.setMessageBody(imMessageBodyEntity);
        messageContent.setMessageKey(imMessageBodyEntity.getMessageKey());
        //发送mq消息   由其他服务进行处理  在messageStore  设置监听器  监听后进行保存到数据库   需要注意的这里消息发送的  队列发生了改变
        rabbitTemplate.convertAndSend(Constants.RabbitConstants.StoreP2PMessage,"",
                JSONObject.toJSONString(dto));
    }


    //进行提取消息的内容
    public ImMessageBody extractMessageBody(MessageContent messageContent){
        ImMessageBody messageBody = new ImMessageBody();
        messageBody.setAppId(messageContent.getAppId());
        messageBody.setMessageKey(snowflakeIdWorker.nextId());    //设置消息的id为雪花算法的id
        messageBody.setCreateTime(System.currentTimeMillis());
        messageBody.setSecurityKey("");
        messageBody.setExtra(messageContent.getExtra());
        messageBody.setDelFlag(DelFlagEnum.NORMAL.getCode());
        messageBody.setMessageTime(messageContent.getMessageTime());
        messageBody.setMessageBody(messageContent.getMessageBody());
        return messageBody;
    }

    //单聊消息
//    public List<ImMessageHistoryEntity> extractToP2PMessageHistory(MessageContent messageContent,
//                                                                   ImMessageBodyEntity imMessageBodyEntity){
//        List<ImMessageHistoryEntity> list = new ArrayList<>();
//        //来自的消息
//        ImMessageHistoryEntity fromHistory = new ImMessageHistoryEntity();
//        BeanUtils.copyProperties(messageContent,fromHistory);
//        fromHistory.setOwnerId(messageContent.getFromId());
//        fromHistory.setMessageKey(imMessageBodyEntity.getMessageKey());
//        fromHistory.setCreateTime(System.currentTimeMillis());
//        //接收的
//        ImMessageHistoryEntity toHistory = new ImMessageHistoryEntity();
//        BeanUtils.copyProperties(messageContent,toHistory);
//        toHistory.setOwnerId(messageContent.getToId());
//        toHistory.setMessageKey(imMessageBodyEntity.getMessageKey());
//        toHistory.setCreateTime(System.currentTimeMillis());
//
//        list.add(fromHistory);
//        list.add(toHistory);
//        return list;
//    }



    @Transactional
    public void storeGroupMessage(GroupChatMessageContent messageContent){

        ImMessageBody imMessageBody = extractMessageBody(messageContent);
        DoStoreGroupMessageDto dto = new DoStoreGroupMessageDto();
        dto.setMessageBody(imMessageBody);
        dto.setGroupChatMessageContent(messageContent);
        //将消息进行发送到mq 后面进行监听 并存到数据库
        rabbitTemplate.convertAndSend(Constants.RabbitConstants.StoreGroupMessage,
                "",
                JSONObject.toJSONString(dto));
        messageContent.setMessageKey(imMessageBody.getMessageKey());
    }


    //进行将消息放在缓存中  防止重复发消息的出现
    public void setMessageFromMessageIdCache(Integer appId,String messageId,Object messageContent){    //使用这样的参数方式是为了 兼容单聊和群聊
        // appid : cache : messageId
        String key =appId + ":" + Constants.RedisConstants.cacheMessage + ":" + messageId;
        stringRedisTemplate.opsForValue().set(key,JSONObject.toJSONString(messageContent),300, TimeUnit.SECONDS);
    }

    //进行从缓存中获取 获取消息
    public <T> T getMessageFromMessageIdCache(Integer appId,String messageId,Class<T> clazz){
        String key = appId + ":" + Constants.RedisConstants.cacheMessage + ":" + messageId;
        String msg = stringRedisTemplate.opsForValue().get(key);
        if (StringUtils.isBlank(msg)){
            return null;
        }
        return JSONObject.parseObject(msg, clazz);
    }


    // 进行存储单人离线消息
    public void storeOfflineMessage(OfflineMessageContent offlineMessage){

        offlineMessage.setConversationId(conversationService.convertConversationId(ConversationTypeEnum.P2P.getCode(),
                offlineMessage.getFromId(),offlineMessage.getToId()));

        //找到fromId的队列
        String fromKey= offlineMessage.getAppId()+":"+Constants.RedisConstants.OfflineMessage+":"+offlineMessage.getFromId();
        //找到toId的队列
        String toKey=offlineMessage.getAppId()+":"+Constants.RedisConstants.OfflineMessage+":"+offlineMessage.getToId();
        //进行判断队列中的数据是否超过设定值
        ZSetOperations<String, String> operations = stringRedisTemplate.opsForZSet();
        if(operations.zCard(fromKey)>appConfig.getOfflineMessageCount()){               //zCard是获取里面的消息数
            operations.removeRange(fromKey,0,0); //进行删除第一个元素
        }
        //单聊 0  群聊 1 机器人 2
        offlineMessage.setConversationId(conversationService.convertConversationId(ConversationTypeEnum.P2P.getCode(),
                offlineMessage.getFromId(),offlineMessage.getToId()));
        //插入 数据 根据messageKey 作为分值
        operations.add(fromKey,JSONObject.toJSONString(offlineMessage),offlineMessage.getMessageKey());
        //进行判断队列中的数据是否超过设定值
        if (operations.zCard(toKey)>appConfig.getOfflineMessageCount()){
            operations.removeRange(toKey,0,0);
        }
        offlineMessage.setConversationId(conversationService.convertConversationId(ConversationTypeEnum.P2P.getCode(),
                offlineMessage.getToId(),offlineMessage.getFromId()));
        //插入 数据 根据messageKey 作为分值
        operations.add(toKey,JSONObject.toJSONString(offlineMessage),offlineMessage.getMessageKey());

    }

    //进行群聊消息的离线存储
    public void storeGroupOfflineMessage(OfflineMessageContent offlineMessage
            ,List<String> memberIds){

        ZSetOperations<String, String> operations = stringRedisTemplate.opsForZSet();
        //判断 队列中的数据是否超过设定值
        offlineMessage.setConversationType(ConversationTypeEnum.GROUP.getCode());

        for (String memberId : memberIds) {
            // 找到toId的队列
            String toKey = offlineMessage.getAppId() + ":" +
                    Constants.RedisConstants.OfflineMessage + ":" +
                    memberId;
            offlineMessage.setConversationId(conversationService.convertConversationId(
                    ConversationTypeEnum.GROUP.getCode(),memberId,offlineMessage.getToId()
            ));
            if(operations.zCard(toKey) > appConfig.getOfflineMessageCount()){
                operations.removeRange(toKey,0,0);         //如果超过就进行删除第一条
            }
            // 插入 数据 根据messageKey 作为分值
            operations.add(toKey,JSONObject.toJSONString(offlineMessage),
                    offlineMessage.getMessageKey());
        }


    }











}
